import Sniffer from 'lib/base/sniffer';
import RAF from 'lib/base/raf';
import EventEmitter from 'lib/base/tiny-emitter';
import Paths from './paths';
import gsap from 'gsap';
import CSSPlugin from 'gsap/CSSPlugin';
import ScrollTrigger from 'gsap/ScrollTrigger';
import ScrollSmoother from 'lib/gsap/esm/ScrollSmoother';
import { log } from 'utils';

const events = {};
const emitter = new EventEmitter();
const env = Paths.env;

// Sniffer
const sniffer = new Sniffer();
sniffer.cssify(document.documentElement);

// Global SPA (Single Page Application) Object
const App = {};

const lowercase = (str) => str.toLowerCase();
const capitalize = (str) =>
    str.toLowerCase().replace(/\b(\w)|\s(\w)/g, (m) => m.toUpperCase());
const removeHeadFootSlash = (str) => str.replace(/(\/{2,}$|^\/{2,})/g, '');
const removeAllSlash = (str) => str.replace(/\//g, '');
const ensureSlash = (str) => str.replace(/([^:]\/)\/+/g, '$1');
const def = (val, defaults) => {
    return val == undefined ? defaults : val;
};

App.lowercase = lowercase;
App.capitalize = capitalize;
App.removeHeadFootSlash = removeHeadFootSlash;
App.removeAllSlash = removeAllSlash;
App.ensureSlash = ensureSlash;
App.def = def;
App.assetsURL = __ASSETS_URL__;
// console.log(__ASSETS_URL__, '__ASSETS_URL__');

Object.assign(App, sniffer.data, Paths, {
    env: env,
    PERF_BAD: 0,
    PERF_LOW: 1,
    PERF_GOOD: 2,
    PERF_HIGH: 3,
    isReady: false,
    isBusy: false,
    isFirstTime: true,
    mouse: {
        x: window.innerWidth / 2,
        y: window.innerHeight / 2,
        halfX: 0,
        halfY: 0,
        touches: null,
        moved: false,
        pressed: false,
        // prevent: false,
        // stop: false,
    },
    on(id, cb) {
        if (!events[id]) events[id] = [];
        const existedEvent = events[id].filter(
            (ev) => ev.type === 'on' && ev.cb === cb
        );

        if (existedEvent.length === 0) {
            events[id].push({ type: 'on', cb: cb });
            emitter.on(id, cb);
        } else {
            // <remove>
            // log('#f00#emitter:on', id + cb + ' is already exsited');
            // </remove>
        }

        // if (!events[id]) {
        // 	events[id] = { type: 'on', cb: cb };
        // 	emitter.on(id, cb);
        // }
        // // <remove>
        // else {
        // 	log('#f00#emitter:on', id + ' is already exsited');
        // }
        // // </remove>
    },
    once(id, cb) {
        if (!events[id]) events[id] = [];
        const existedEvent = events[id].filter(
            (ev) => ev.type === 'once' && ev.cb === cb
        );

        if (existedEvent.length === 0) {
            events[id].push({ type: 'once', cb: cb });
            emitter.once(id, cb);
        } else {
            // <remove>
            // log('#f00#emitter:once', id + cb + ' is already exsited');
            // </remove>
        }

        // if (!events[id]) {
        // 	events[id] = { type: 'once', cb: cb };
        // 	emitter.once(id, cb);
        // }
        // // <remove>
        // else {
        // 	log('#f00#emitter:once', id + ' is already exsited');
        // }
        // // </remove>
    },
    off(id, cb) {
        if (cb) {
            if (events[id]) {
                const newIDEvents = [];

                for (let i = 0; i < events[id].length; i++) {
                    if (events[id][i].cb !== cb) {
                        newIDEvents.push(events[id][i]);
                    }
                }

                newIDEvents.length
                    ? (events[id] = newIDEvents)
                    : delete events[id];
                emitter.off(id, cb);
            }
        } else if (Array.isArray(id)) {
            id.forEach((i) => off(i));
        } else {
            const evs = events[id];
            (evs || []).forEach((e) => emitter.off(id, e));
        }
        // const offEvent = (id) => {
        // 	if (events[id]) {
        // 		emitter.off(id, events[id].cb);
        // 		events[id] = null;
        // 		delete events[id];
        // 	}
        // 	// <remove>
        // 	else {
        // 		log('#f00#emitter:off', id + " doesn't exist");
        // 	}
        // 	// </remove>
        // };
        // if (Array.isArray(param)) {
        // 	for (const str of param) {
        // 		offEvent(str);
        // 	}
        // } else {
        // 	offEvent(param);
        // }
    },
    trigger(...args) {
        const id = args[0];
        if (events[id]) {
            // if (events[id].type == 'once') {
            //     events[id] = null;
            //     delete events[id];
            // }
            // emitter.emit(id, ...args.splice(1));
            const newEvents = [];

            // console.log(id, events[id]);

            for (let i = 0; i < events[id].length; i++) {
                if (events[id][i].type !== 'once')
                    newEvents.push(events[id][i]);
            }

            newEvents.length ? (events[id] = newEvents) : delete events[id];

            emitter.emit(id, ...args.splice(1));
        }
        // <remove>
        else {
            log('#f00#emitter:trigger', id + " doesn't exist");
        }
        // </remove>
    },
});

gsap.registerPlugin(CSSPlugin, ScrollTrigger, ScrollSmoother);

// RAF
// App.raf.on('event:name', function);
// App.raf.off('event:name')
// App.raf.setTimeout() // auto clear
// const intervalId = App.raf.setInterval( function, delayTime );
// App.raf.clearInterval( intervalId );
App.raf = new RAF();

// <remove>
// log('#4b7#raf', 'App.raf started');
// log(
//     '#29b#Sniffer_CPU_GPU',
//     App.system.name,
//     App.browser.name + ': ' + App.browser.version + ' ——',
//     'CPU:',
//     App.CPU.perf,
//     '——',
//     'GPU:',
//     App.GPU.tier,
//     ' /',
//     'R:',
//     App.GPU.rank,
//     'Graphic Card:',
//     App.GPU.type
// );
// </remove>

export default App;
